/********************************************************/
/*	Copyright (C) 2016 Gong Li Bin		 	*/
/*	Project:	GlbLib-1.0.0			*/
/*	Author:		gong_libin			*/
/*	Date:		2016_06_01			*/
/*	File:		GlbRawTest.cpp			*/
/********************************************************/

#include "GlbRaw.h"
#include "GlbTime.h"
#include <getopt.h>

using namespace GlbNet;

void GlbRawTestCore(CGlbRaw& rCRaw, USHORT usPort)
{
	int iLength = 0;
	USHORT usDst = 0;
	struct ip* pstIP = NULL;
	struct tcphdr* pstTcp = NULL;
	struct udphdr* pstUdp = NULL;
	struct ether_header* pstEth = NULL;
	UCHAR uszRecv[GLB_KBYTES2] = { 0 };

	while (true) {
		iLength = rCRaw.GlbNetRecv(uszRecv, GLB_KBYTES2);

		pstEth = (struct ether_header*)uszRecv;
		pstIP = (struct ip*)(uszRecv + sizeof(struct ether_header));
		switch (pstIP->ip_p) {
			case GLB_IPPROTO_TCP:
				pstTcp = (struct tcphdr*)(uszRecv + sizeof(struct ether_header) + pstIP->ip_hl * 4);
				usDst = ntohs(pstTcp->th_dport);
				break;
			case GLB_IPPROTO_UDP:
				pstUdp = (struct udphdr*)(uszRecv + sizeof(struct ether_header) + pstIP->ip_hl * 4);
				usDst = ntohs(pstUdp->uh_dport);
				break;
			default:
				break;
		}

		if (iLength > 150 && usDst == usPort) {
			GLB_PRINT("SrcMac: %02x:%02x:%02x:%02x:%02x:%02x\t",
				pstEth->ether_shost[0], pstEth->ether_shost[1], pstEth->ether_shost[2],
				pstEth->ether_shost[3], pstEth->ether_shost[4], pstEth->ether_shost[5]);
			GLB_PRINT("DstMac: %02x:%02x:%02x:%02x:%02x:%02x\n",
				pstEth->ether_dhost[0], pstEth->ether_dhost[1], pstEth->ether_dhost[2],
				pstEth->ether_dhost[3], pstEth->ether_dhost[4], pstEth->ether_dhost[5]);
			GLB_PRINT("SrcAddr: %s\t", (char*)inet_ntoa(pstIP->ip_src));
			GLB_PRINT("DstAddr: %s\n", (char*)inet_ntoa(pstIP->ip_dst));
			if (NULL != pstTcp) {
				GLB_PRINT("Protocol: TCP\n");
				GLB_PRINT("SrcPort: %d\t", ntohs(pstTcp->th_sport));
				GLB_PRINT("DstPort: %d\n", ntohs(pstTcp->th_dport));
				GLB_PRINT("Recv: %s\n\n", uszRecv + sizeof(struct ether_header) + pstIP->ip_hl * 4 + pstTcp->th_off * 4);
				pstTcp = NULL;
			}
			else if (NULL != pstUdp) {
				GLB_PRINT("Protocol: UDP\n");
				GLB_PRINT("SrcPort: %d\t", ntohs(pstUdp->uh_sport));
				GLB_PRINT("DstPort: %d\n", ntohs(pstUdp->uh_dport));
				GLB_PRINT("Recv: %s\n\n", uszRecv + sizeof(struct ether_header) + pstIP->ip_hl * 4 + sizeof(struct udphdr));
				pstUdp = NULL;
			}
			else {
			}
		}

		memset(uszRecv, '\0', GLB_KBYTES2);
		usDst = 0;
	}

	return;
}

int main(int argc, char* argv[])
{
	CGlbRaw CRaw;
 	int iIndex = 0;
	int iReturn = 0;
	USHORT usPort = 80;
	char* pszDev = (char*)"eth0";

	struct option stOptions[] = {
		{"dev", 1, 0, 'd'},
		{"port", 1, 0, 'p'},
		{"help", 0, 0, 'h'},
		{0, 0, 0, 0},
	};

	while (true) {
		if (GLB_FAILURE != (iReturn = getopt_long(argc, argv, "d:p:h", stOptions, &iIndex))) {
			switch (iReturn) {
				case 'd':
					pszDev = optarg;
					break;
				case 'p':
					usPort = atoi(optarg);
					break;
				case 'h':
					GLB_PRINT("Usage: %s [options]\n", argv[0]);
					GLB_PRINT("Valid options are:\n");
					GLB_PRINT("[0] -d or --dev:       set dev\n");
					GLB_PRINT("[0] -p or --port:      set port\n");
					GLB_PRINT("[0] -h or --help:      show help.\n");
					return GLB_SUCCESS;
				default:
					return GLB_SUCCESS;
			}
		}
		else {
			break;
		}
	}

	if (GLB_SUCCESS == CRaw.GlbRawInitRecv(GLB_PF_PACKET, GLB_SOCK_RAW, htons(ETH_P_ALL))) {
		GlbRawTestCore(CRaw, usPort);
		CRaw.GlbNetClose();
	}
	else {
		GLB_PRINT("Failed to GlbRawOpen\n");
	}

	return GLB_SUCCESS;
}
